Android — Activity 异常情况下的生命周期
前言
看了任玉刚老师的 living 之后,只能说大牛就是大牛。怀着敬畏的态度研读他的著作 — 《Android 开发艺术探索》,毫不夸张的说这本书绝对算是 Android 进阶必读书了。本菜鸡看了第一章就收获颇丰,以下就是一些读书笔记,例子都是枪书上的,感谢任老师。
Activity 正常情况下的生命周期估计大家随口都能说出,那么在异常情况下的生命周期你知道吗?首先,哪些是异常情况呢?emmmm,有以下常见的两种情况:
- 资源相关的系统配置发生改变导致 Activity 被杀死并重新创建。
- 资源内存不足导致低优先级的 Activity 被杀死
对于情况一,乍一听可能有点懵,那就举一个实例 — 横竖屏的切换。我们知道,在这种情况下,Activity 是销毁后再重新创建的,当然,我们也可以阻止系统重新创建Activity 。但是,他不会是简单的销毁重建,为什么这么说呢?让我们页面上的视频时,看到一半我们切换到全屏,这时候它会保存我们的观看进度,那这是这么实现的呢?对于情况二,这个还真的不好模拟,那就只能理论分析咯。
情况一:
当系统配置发生改变之后,Activity 会被销毁,其 onPause、onStop、onDestroy 均会被调用,同时由于Activity 是在异常情况下终止的,系统会调用 onSaveInstanceState 来保存当前Activity 的状态。这个方法调用是在 onStop 之前,它和 onPause 没有既定的时序关系,即可能在 onPause 之前,也可能在它之后。需要强调的是,这个方法只会在Activity 被异常终止的情况下才会调用,正常情况下,系统不会调用这个方法。当Activity 被重新创建的时候,系统会调用 onRestoreInstanceState 方法,并且把Activity 销毁时 onSaveInstanceState 方法所保存的 Bundle 对象同时作为参数传递给 onRestoreInstanceState 和 onCreat 方法。因此,我们可以通过 onRestoreInstanceState 和 onCreat 方法来判断 Activity 是否被重建了,如果被重建了,那么我们可以取出之前保存的数据并恢复。从时序上来说,onRestoreInstanceState 的调用时机在 onStart 之后。
同时,我们要知道,在 onSaveInstanceState 和 onRestoreInstanceState 方法中,系统自动为我们做了一定的恢复工作。当 Activity 在异常情况下需要重新创建时,系统会默认为我们保存当前 Activity 的视图结构,并且在 Activity 重启后为我们恢复这些数据,比如文本框用户输入的数据、ListView 滚动的位置等等。
验证:
我们可以模拟一个实例,点击按钮进行横竖屏的切换:
|
|
以下是点击按钮之后打印的日志:
显然,onSaveInstanceState 是在 onStop 之前调用,onRestoreInstanceState 是在 onStart 之后调用。而且,可以看到,在重新创建 Activity 的时候,onCreat 方法里面的 Bundle 参数已经有值了,该参数也就是 onSaveInstanceState 传递过来的 Bundle 对象。
情况二:
先简单描述一下 Activity 的优先级情况,按照优先级从高到低,可以分为一下三种:
- 前台 Activity ——-正在和用户交互的 Activity ,优先级最高。
- 可见但非前台 Activity ——-比如 Activity 中弹出了一个对话框,导致 Activity 可见但是位于后台无法和用户交互。
- 后台 Activity ——已经被暂停的 Activity ,比如执行了 onStop,优先级最低。
当系统内存不足时,系统会按照上述优先级去销毁目标 Activity 所在的进程 ,并在后续通过 onSaveInstanceState 和 onRestoreInstanceState 来存储和恢复数据。如果一个进程中没有四大组件在执行,那么这个进程很快就会被系统杀死。因此,一些后台工作不适合脱离四大组件独立运行在后台中,这样进程很快就会被杀死。比较好的办法是将后台工作放入 Service 中从而保证进程有一定的优先级,这样就不会轻易的被系统杀死。
更新
前面说过,在系统配置发生改变后,是可以不用重新创建 Activity 的。如果不想重新创建,可以给 Activity 指定configChanges 属性。比如不想让 Activity 在屏幕旋转的时候重新创建,就可以以下:
|
|
如果我们想指定多值,可以用 | 分隔。以下列举一些常用的:
类型 | 含义 |
---|---|
keyboardHidden | 键盘的可访问性发生了改变,比如用户调出了键盘 |
screenLayout | 屏幕布局发生了改变,很可能是用户激活了另外一个显示设备 |
fontScale | 系统字体缩放比例发生了改变,比如用户选择了一个新字号 |
uiMode | 用户界面模式发生了改变,比如用户开启了夜间模式(API 8 新添加) |
orientation | 屏幕方向发生了改变,这个是最常用的,比如旋转了手机屏幕 |